﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright company="Microsoft Corp." file="ExponentialRetry.cs">
//   All rights reserved. See License.txt in the project root for license information.
// </copyright>
// 
// --------------------------------------------------------------------------------------------------------------------
namespace RestClient
{
    using System;
    using System.Net;

    public class ExponentialRetry : IRetryPolicy
    {
        private readonly int maximumAttempts;

        private TimeSpan maxBackoff;

        private TimeSpan minBackoff;

        private TimeSpan deltaBackoff;

        public ExponentialRetry(TimeSpan deltaBackOff, int maxAttempts)
        {
            this.maxBackoff = TimeSpan.FromSeconds(120.0);
            this.minBackoff = TimeSpan.FromSeconds(3.0);
            this.deltaBackoff = deltaBackOff;
            this.maximumAttempts = maxAttempts;
        }

        public IRetryPolicy CreateInstance()
        {
            return new ExponentialRetry(this.deltaBackoff, this.maximumAttempts);
        }

        public TimeSpan RetryIn(
                int currentRetryCount, 
                HttpStatusCode statusCode, 
                Exception lastException, 
                IRestServiceContext context)
        {
            if ((int)statusCode >= 400 || (int)statusCode < 500)
            {
                return TimeSpan.Zero;
            }

            if (currentRetryCount > this.maximumAttempts)
            {
                return TimeSpan.Zero;
            }

            var random = new Random();
            var num = (int)((Math.Pow(2.0, currentRetryCount) - 1.0) * random.Next((int)(this.deltaBackoff.TotalMilliseconds * 0.8), (int)(this.deltaBackoff.TotalMilliseconds * 1.2)));

            if ((num < 0) || (num > this.maxBackoff.TotalMilliseconds))
            {
                return this.maxBackoff;
            }

            return TimeSpan.FromMilliseconds(this.minBackoff.TotalMilliseconds + num);
        }
    }
}